#ifndef __QE_ARGPARSE_H__
#define __QE_ARGPARSE_H__



#include "qe_def.h"



struct qe_argument_parse;
struct qe_argparse_option;
typedef struct qe_argument_parse qe_argparse;
typedef struct qe_argparse_option qe_option;

typedef qe_ret (*qe_argp_callback)(qe_argparse *parse, 
    qe_option *option);


typedef enum {
    /* special */
    QE_OPTION_END,
    QE_OPTION_GROUP,
    QE_OPTION_HELP,
    QE_OPTION_ACTION,
    QE_OPTION_SUBCMD,
    /* options with no arguments */
    QE_OPTION_BOOLEAN,
    QE_OPTION_BIT,
    /* options with arguments (optional or required) */
    QE_OPTION_INTEGER,
    QE_OPTION_FLOAT,
    QE_OPTION_STRING
} qe_option_type;

typedef enum {
    QE_OPTION_UNSET = 1 << 0,
} qe_option_flag;

typedef struct qe_argparse_option
{
    qe_option_type type;
    const char short_name;
    qe_const_str long_name;
    qe_ptr value;
    qe_const_str help;
    qe_ubase data;
    qe_u32 flags;
    qe_argp_callback callback;
} qe_option;

typedef struct qe_argument_parse
{
    qe_option *options;
    qe_const_str *usages;
    qe_const_str description;
    qe_const_str epilog;
    qe_int argc;
    qe_const_str *argv;
    qe_const_str *outv;
    qe_int cpidx;
    const char *opt;
} qe_argparse;

#define qe_option_data(opt)     ((opt)->data)
#define qe_option_value(opt)    ((opt)->value)
#define qe_option_string(opt)   (*(qe_str *)((opt)->value))
#define qe_option_integer(opt)  (*(qe_int *)((opt)->value))
#define qe_option_float(opt)    (*(qe_double *)((opt)->value))
#define qe_option_boolean(opt)  (*(qe_bool *)((opt)->value))
#define qe_option_mask(opt)     (*(qe_u32 *)((opt)->value))


qe_ret qe_argp_help_cb_no_exit(qe_argparse *parse, qe_option *option);

#define QE_OPT_ITEM(type, sname, lname, help, val, data, flags, cb) \
    {type, sname, lname, val, help, (qe_ubase)data, flags, cb}

#define QE_OPT_END() \
    QE_OPT_ITEM(QE_OPTION_END, 0, QE_NULL, QE_NULL, QE_NULL, 0, 0, QE_NULL)

#define QE_OPT_HELP(sname, lname, help) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        QE_NULL, 0, 0, qe_argp_help_cb_no_exit)

#define QE_OPT_BOOLEAN(sname, lname, help, val, flag) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        val, 0, flag, QE_NULL)

#define QE_OPT_TRUE(sname, lname, help, val) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        val, 0, 0, QE_NULL)

#define QE_OPT_FALSE(sname, lname, help, val) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        val, 0, QE_OPTION_UNSET, QE_NULL)

#define QE_OPT_BIT(sname, lname, help, val, bit, flag) \
    QE_OPT_ITEM(QE_OPTION_BIT, sname, lname, help, \
        val, bit, flag, QE_NULL)

#define QE_OPT_MASK(sname, lname, help, val, bit) \
    QE_OPT_ITEM(QE_OPTION_BIT, sname, lname, help, \
        val, bit, 0, QE_NULL)

#define QE_OPT_UNMASK(sname, lname, help, val, bit) \
    QE_OPT_ITEM(QE_OPTION_BIT, sname, lname, help, \
        val, bit, QE_OPTION_UNSET, QE_NULL)

#define QE_OPT_INTEGER(sname, lname, help, val) \
    QE_OPT_ITEM(QE_OPTION_INTEGER, sname, lname, help, \
        val, 0, 0, QE_NULL)

#define QE_OPT_FLOAT(sname, lname, help, val) \
    QE_OPT_ITEM(QE_OPTION_FLOAT, sname, lname, help, \
        val, 0, 0, QE_NULL)

#define QE_OPT_STRING(sname, lname, help, val) \
    QE_OPT_ITEM(QE_OPTION_STRING, sname, lname, help, \
        val, 0, 0, QE_NULL)

#define QE_OPT_GROUP(help) \
    QE_OPT_ITEM(QE_OPTION_GROUP, QE_NULL, QE_NULL, help, \
        QE_NULL, 0, 0, QE_NULL)

#define QE_OPT_SUBCMD(lname, help, data, cb) \
    QE_OPT_ITEM(QE_OPTION_SUBCMD, QE_NULL, lname, help, \
        QE_NULL, 0, 0, cb)

#define QE_OPT_ACTION(sname, lname, help, data, cb) \
    QE_OPT_ITEM(QE_OPTION_ACTION, sname, lname, help, \
        QE_NULL, data, 0, cb)

#define QE_ACT_INTEGER(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_INTEGER, sname, lname, help, \
        val, data, 0, cb)

#define QE_ACT_STRING(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_STRING, sname, lname, help, \
        val, data, 0, cb)

#define QE_ACT_FLOAT(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_FLOAT, sname, lname, help, \
        val, data, 0, cb)

#define QE_ACT_BIT(sname, lname, help, val, data, flag, cb) \
    QE_OPT_ITEM(QE_OPTION_BIT, sname, lname, help, \
        val, data, flag, cb)

#define QE_ACT_BOOLEAN(sname, lname, help, val, data, flag, cb) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        val, data, flag, cb)

#define QE_ACT_TRUE(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        val, data, 0, cb)

#define QE_ACT_FALSE(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_BOOLEAN, sname, lname, help, \
        val, data, QE_OPTION_UNSET, cb)

#define QE_ACT_MASK(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_BIT, sname, lname, help, \
        val, data, 0, cb)

#define QE_ACT_UNMASK(sname, lname, help, val, data, cb) \
    QE_OPT_ITEM(QE_OPTION_BIT, sname, lname, help, \
        val, data, QE_OPTION_UNSET, cb)

qe_ret qe_argp_init(qe_argparse *argp, qe_option *options, 
    qe_const_str *usages, qe_const_str description, qe_const_str epilog);

qe_ret qe_argp_parse(qe_argparse *argp, qe_int argc, qe_const_str *argv);

void qe_argp_usage(qe_argparse *argp);



#endif /* __QE_ARGPARSE_H__ */